<?php
/**
 * Nordic Repository
 * 
 * LICENSE
 * 
 * The new BSD license is applied on this source-file. For further
 * information please visit http://license.nordic-dev.de/newbsd.txt
 * or send an email to andre.moelle@gmail.com.
 */

/**
 * Necessary includes.
 */
require_once('functions.php');
require_once('Zend/Loader.php');

Zend_Loader::loadClass('Zend_Registry');

/**
 * Class which handles the application.
 * 
 * @category   Nordic
 * @package    Nordic
 * @copyright  2007 Nordic Development
 * @license    http://license.nordic-dev.de/newbsd.txt (New-BSD license)
 * @author     Andre Moelle <andre.moelle@gmail.com>
 * @version    $Id: Nordic.php 3 2007-07-08 09:21:42Z andre.moelle $
 */
final class Nordic
{
	/**
	 * Enviroment.
	 * 
	 * @var string
	 */
	private $_env;
	
	/**
	 * Response-object.
	 * 
	 * @var Zend_Controller_Response_Abstract
	 */
	private $_response;
	
	/**
	 * Start-time of the application.
	 * 
	 * @var float
	 */
	private $_start = 0.0;
	
	/**
	 * Starts the application.
	 * 
	 * In detail it loads the __autoload-function and configures
	 * the front-controller.
	 * 
	 * @param string $env environment (@see _setUpEnviroment())
	 * @param float $start start-time
	 * @return void
	 */
	public function __construct ($env, $start = 0.0)
	{
		$this->_start = $start;
		
		$this->_advertise();
		$this->_setUpEnvironment(strtolower($env));
		$this->_initConfig();
	}
	
	/**
	 * Returns the application as string.
	 * 
	 * @param void
	 * @return string
	 */
	public function __toString ()
	{
		$result = '';
		
		if(!$this->getResponse())
		{
			return $result;
		}
		
		$pagebuilder = Nordic_Pagebuilder::getInstance();
		$pagebuilder->assign('loggedIn', Zend_Auth::getInstance()->hasIdentity());
		
		switch ($this->_env)
		{
			case 'production':
				break;
				
			case 'development':
				$this->displayProfiler();
			case 'test':
				$this->getResponse()->renderExceptions(true);
				
				break;
		}
		
		$result = $pagebuilder->render($this->getResponse());
		
		if($this->_start)
		{
			$result .= "\r\n" . '<!-- ' .
				sprintf('%.06f', microtime(true) - $this->_start) . 's -->';
		}
		
		return $result;
	}
	
	/**
	 * Sends the X-Powered-By-header for advertising.
	 * 
	 * @param void
	 * @return void
	 */
	private function _advertise ()
	{
		header('X-Powered-By: Nordic Repository 0.1.0-dev');
	}
	
	/**
	 * Initializes the authentication.
	 * 
	 * @param void
	 * @return void
	 */
	private function _initAuth ()
	{
		Zend_Loader::loadClass('Nordic_Auth');
		
		Zend_Auth::getInstance()
			->setStorage(new Zend_Auth_Storage_Session('identity'));
	}
	
	/**
	 * Initializes the config-object.
	 * 
	 * @param void
	 * @return void
	 */
	private function _initConfig ()
	{
		Zend_Loader::loadClass('Nordic_Config');
		
		Nordic_Config::getInstance(
			array(
				'php' => 'Nordic_Config_Php'
			)
		);
	}
	
	/**
	 * Initializes the controller.
	 * 
	 * @param void
	 * @return void
	 */
	private function _initController ()
	{
		Zend_Loader::loadClass('Zend_Controller_Front');
		Zend_Loader::loadClass('Zend_Controller_Action_HelperBroker');
		Zend_Loader::loadClass('Zend_Controller_Plugin_ErrorHandler');
		
		Zend_Loader::loadClass('Nordic_Security_Protector');
		Zend_Loader::loadClass('Nordic_Controller_Route');
		Zend_Loader::loadClass('Nordic_Controller_Helper_Rerouter');
		Zend_Loader::loadClass('Nordic_Controller_Helper_Translator');
		Zend_Loader::loadClass('Nordic_Controller_Helper_Config');
		Zend_Loader::loadClass('Nordic_Pagebuilder');
		
		$front = Zend_Controller_Front::getInstance();
		$front->setControllerDirectory(NORDIC_CONTROLLER);
		$front->returnResponse(true);
		$front->registerPlugin(new Nordic_Security_Protector($front->getDispatcher()));
		
		Zend_Controller_Action_HelperBroker::removeHelper('ViewRenderer');
		Zend_Controller_Action_HelperBroker::addHelper(
			new Nordic_Controller_Helper_Rerouter()
		);
		Zend_Controller_Action_HelperBroker::addHelper(
			new Nordic_Controller_Helper_Translator()
		);
		Zend_Controller_Action_HelperBroker::addHelper(
			new Nordic_Controller_Helper_Config()
		);
		
		$pagebuilder = new Nordic_Pagebuilder($front->getResponse());
		
		Zend_Controller_Action_HelperBroker::addHelper($pagebuilder);
		
		$router = $front->getRouter();
		$router->removeDefaultRoutes();
		$router->addRoute('Nordic', new Nordic_Controller_Route(
				array(),
				$front->getDispatcher(),
				$front->getRequest()
			)
		);
	}
	
	/**
	 * Initializes the session and the necessary variable.
	 * 
	 * @param void
	 * @return void
	 */
	private function _initSession ()
	{
		Zend_Loader::loadClass('Zend_Session');
		
		Zend_Session::start();
		
		Zend_Registry::set('Application', new Zend_Session_Namespace('Application'));
		
		$app = Zend_Registry::get('Application');
		
		if(!isset($app->language))
		{
			$app->language = Nordic_I18n::getInstance()->getLanguage();
		}
	}
	
	/**
	 * Initializes the translator.
	 * 
	 * @param void
	 * @return boolean
	 */
	private function _initTranslator ()
	{
		Zend_loader::loadClass('Zend_Translate');
		
		try
		{
			Zend_Registry::get('Translator');
			return false;
		}
		catch (Zend_Exception $e)
		{
			;
		}
		
		Zend_Registry::set(
			'Translator',
			new Zend_Translate(
				'array',
				array(),
				Zend_Registry::get('Application')->language
			)
		);
		
		return true;
	}
	
	/**
	 * Initializes the view-factory.
	 * 
	 * @param void
	 * @return void
	 */
	private function _initView ()
	{
		Zend_Loader::loadClass('Nordic_View');
		Zend_Loader::loadClass('Nordic_View_Factory');
		
		Nordic_View_Factory::setView(new Nordic_View());
		
		$factory = Nordic_View_Factory::getInstance();
		$factory->setScriptPath(NORDIC_VIEW);
		$factory->addHelperPath(
			NORDIC_VIEW . 'helpers',
			'App_Helper_'
		);
		
		$factory->translator = Zend_Registry::get('Translator');
	}
	
	/**
	 * Sets up the appropriate enviroment.
	 * 
	 * Following environments are available:
	 * - development (the application is developed)
	 * - test (the entire application is tested)
	 * - production (the application is online)
	 * 
	 * @param string $env environment
	 * @return void
	 */
	private function _setUpEnvironment ($env)
	{
		$this->_env = $env;
		
		switch ($env)
		{
			case 'test':
			case 'development':
				ini_set('display_errors', 1);
				error_reporting(E_ALL);
				
				
				break;
			case 'production':
				error_reporting(0);
				ini_set('display_errors', 0);
				
				break;
		}
	}
	
	/**
	 * Tries to authenticate the user using the cookie.
	 * 
	 * The result is a boolean which determines if the user is logged
	 * in.
	 * 
	 * @param void
	 * @return boolean
	 */
	private function _performLogin ()
	{
		Zend_Loader::loadClass('Zend_Auth');
		Zend_Loader::loadClass('Nordic_Auth');
		
		if(Zend_Auth::getInstance()->hasIdentity())
		{
			return true;
		}
		
		Zend_Auth::getInstance()->authenticate(new Nordic_Auth(null, array()));
		
		return Zend_Auth::getInstance()->hasIdentity();
	}
	
	/**
	 * Configures the database using a specified config.
	 * 
	 * @param string $config config-filename
	 * @return void
	 */
	public function configureDatabase ($config)
	{
		Zend_Loader::loadClass('Nordic_Config_Php');
		Zend_Loader::loadClass('Zend_Db');
		Zend_Loader::loadClass('Zend_Db_Table');
		
		$conf = Nordic_Config::getInstance()->load(
			$config,
			array(
				'section' => $this->_env
			)
		);
		$db = Zend_Db::factory($conf->type, $conf->toArray());
		
		Zend_Registry::set('Zend_Db', $db);
		Zend_Db_Table::setDefaultAdapter($db);
	}
	
	/**
	 * Displays the content of the profiler if needed.
	 * 
	 * @param void
	 * @return string
	 */
	public function displayProfiler ()
	{
		try
		{
			$profiler = Zend_Registry::get('Zend_Db')->getProfiler();
			
			if(!$profiler->getTotalNumQueries())
			{
				throw new Zend_Exception();
			}
		}
		catch (Zend_Exception $e)
		{
			return '';
		}
		
		$totalTime    = $profiler->getTotalElapsedSecs();
		$queryCount   = $profiler->getTotalNumQueries();
		$longestTime  = 0;
		$longestQuery = null;
		
		foreach ($profiler->getQueryProfiles() as $query)
		{
		    if($query->getElapsedSecs() > $longestTime)
		    {
		        $longestTime  = $query->getElapsedSecs();
		        $longestQuery = $query->getQuery();
		    }
		}
		
		$result  = "\r\n" . '<!--' . "\r\n";
		$result .= 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "\n";
		$result .= 'Average query length: ' . $totalTime / $queryCount . ' seconds' . "\n";
		$result .= 'Queries per second: ' . $queryCount / $totalTime . "\n";
		$result .= 'Longest query length: ' . $longestTime . "\n";
		$result .= "Longest query: \n" . $longestQuery . "\n";
		$result .= '-->';
		
		return $result;
	}
	
	/**
	 * Returns the response-object.
	 * 
	 * @param void
	 * @return Zend_Controller_Response_Abstract
	 */
	public function getResponse ()
	{
		return $this->_response;
	}
	
	/**
	 * Initializes the application.
	 * 
	 * @param void
	 * @return void
	 */
	public function init ()
	{
		Zend_Loader::loadClass('Nordic_Pagebuilder');
		
		$this->_initSession();
		$this->_initTranslator();
		$this->_initController();
		$this->_initView();
		$this->_initAuth();
	}
	
	/**
	 * Runs the application.
	 * 
	 * It returns the output of the request.
	 * 
	 * @param void
	 * @return void
	 */
	public function run ()
	{
		$this->_performLogin();
		
		$this->_response = Zend_Controller_Front::getInstance()->dispatch();
	}
}
?>